2020_mohr_divisibility_i_ii_iii.py

#

SPDX-FileCopyrightText: 2020 Christophe Demiralp & Kadir Kaya SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be

SPDX-License-Identifier: GPL-3.0-or-later

#

Projet Divisibility I , II, III de Manfred Mohr Christophe Demiralp, Kadir Kaya

import bpy
import math
import random
from random import randint
from math import radians
from math import cos
from math import sin
#

Effacer tout avant de relancer le code

def nettoyage():
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.delete(use_global=False)
    bpy.ops.outliner.orphans_purge()


liste1 = []
liste2 = []
liste_bool_dessine = [
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
]
#

Création des outils de travail en connexion avec Blender et Python

#

Permet de selectionner plusieurs cubes à la fois

def select_multiple(cube):
#

Deselectionner tout les objects

    bpy.ops.object.select_all(action="DESELECT")

    for o in bpy.data.objects:
        if o.name in (cube):

            o.select_set(True)
#

Edit mode

def Edit():
    bpy.ops.object.editmode_toggle()
#

Boolean = Division

def Boolean(un, deux):

    bpy.ops.object.select_all(action="DESELECT")
#

un = Selectionne le cube que l’on désire appliquer un Boolean

    bpy.data.objects[un].select_set
    bpy.ops.object.modifier_add(type="BOOLEAN")
    bpy.context.object.modifiers["Boolean"].operation = "DIFFERENCE"
#

deux = Selectionne le deuxieme cube

    bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[deux]
    bpy.ops.object.modifier_apply(modifier="Boolean")
#

Permet de supprimer les cubes que l’on desire

def delete_quadrants(cube1, cube2, cube3, cube4):

    select_multiple([cube1, cube2, cube3, cube4])
    bpy.ops.object.delete(use_global=False)
#

Extraire les faces et épaissir les arretes

def wireframe(cube):
    cube = bpy.ops.object.modifier_add(type="WIREFRAME")
    bpy.context.object.modifiers["Wireframe"].thickness = 0.2
#

Appliquer une rotation aléatoire sur les trois axes x,y,z

def Rotation_aléatoire(rot):
    rot = random.uniform(0, 3.3)
#

random.uniform = aléatoire

    bpy.ops.transform.rotate(
        value=-rot,
        orient_matrix=(
            (random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
            (random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
            (random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)),
        ),
    )
#

Appliquer une rotation aléatoire sur l’axe x et l’axe y

def Rotation_xy(cube):
    r = random.uniform(0, 3.3)
    t = random.uniform(0, 1.7)
#

cube = bpy.ops.transform.rotate(value=-1, orient_matrix=((0, 0, 0), (1, 1, 0), (0, 0, 0)), constraint_axis=(False,True,False))

    bpy.ops.transform.rotate(
        value=r,
        orient_axis="Y",
        orient_type="GLOBAL",
        orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
        orient_matrix_type="GLOBAL",
        constraint_axis=(False, True, False),
        mirror=True,
        use_proportional_edit=False,
        proportional_edit_falloff="SMOOTH",
        proportional_size=1,
        use_proportional_connected=False,
        use_proportional_projected=False,
    )
    bpy.ops.transform.rotate(
        value=-t,
        orient_axis="X",
        orient_type="GLOBAL",
        orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
        orient_matrix_type="GLOBAL",
        constraint_axis=(True, False, False),
        mirror=True,
        use_proportional_edit=False,
        proportional_edit_falloff="SMOOTH",
        proportional_size=1,
        use_proportional_connected=False,
        use_proportional_projected=False,
    )
    return r, t
#

Appliquer une rotation prècise sur l’axe ( Va nous permettre de réappliquer la rotation du cube centre prècedent)

def Rotation_centre(r, t, cube):
    bpy.ops.transform.rotate(
        value=r,
        orient_axis="Y",
        orient_type="GLOBAL",
        orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
        orient_matrix_type="GLOBAL",
        constraint_axis=(False, True, False),
        mirror=True,
        use_proportional_edit=False,
        proportional_edit_falloff="SMOOTH",
        proportional_size=1,
        use_proportional_connected=False,
        use_proportional_projected=False,
    )
    bpy.ops.transform.rotate(
        value=-t,
        orient_axis="X",
        orient_type="GLOBAL",
        orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
        orient_matrix_type="GLOBAL",
        constraint_axis=(True, False, False),
        mirror=True,
        use_proportional_edit=False,
        proportional_edit_falloff="SMOOTH",
        proportional_size=1,
        use_proportional_connected=False,
        use_proportional_projected=False,
    )
#

Redefinir l’origine du cube pou rbien le positionner et appliquer une rotation avec nouvel origin

def transform_origin(cube):
    bpy.ops.object.select_all(action="DESELECT")
    objectToSelect = bpy.data.objects[cube]
    objectToSelect.select_set(True)
    bpy.context.view_layer.objects.active = objectToSelect
    bpy.context.scene.tool_settings.use_transform_data_origin = True
    bpy.ops.transform.translate(
        value=(-1, -1, -1),
        orient_type="GLOBAL",
        orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
        orient_matrix_type="GLOBAL",
        mirror=True,
        use_proportional_edit=False,
        proportional_edit_falloff="SMOOTH",
        proportional_size=1,
        use_proportional_connected=False,
        use_proportional_projected=False,
    )
    bpy.context.scene.tool_settings.use_transform_data_origin = False
#

Remettre l’origin qu centre pour le positionnement du cube prochain

def origin_centre(cube):
    bpy.ops.object.select_all(action="DESELECT")
    objectToSelect = bpy.data.objects[cube]
    objectToSelect.select_set(True)
    bpy.context.view_layer.objects.active = objectToSelect
    bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS", center="MEDIAN")
#

Projection isométrique et trimetrique

def axoCam(projection, canon):
    bpy.ops.object.camera_add()
    maScene = bpy.context.scene.render
    monAxoCam = bpy.context.object
    monAxoCam.data.type = "ORTHO"
    monAxoCam.data.ortho_scale = 25
    if projection == "axonometrique":
        if canon == "isometrie":  # OK
            monAxoCam.name = "axoIsometrie"
            monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
            monAxoCam.location = (10, 0, 10)
            maScene.pixel_aspect_x = 1
        if canon == "trimetrie":  # OK
            monAxoCam.name = "axoTrimetrie"
            monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
            monAxoCam.location = (20, -18, 16)
            maScene.pixel_aspect_x = 1
#

Début du projet après les outils nécessaires

#

Définition pour créer un cube

def cube(x, y, z, nom):
    cube = bpy.ops.mesh.primitive_cube_add(size=2, location=(x, y, z), scale=(2, 2, 2))
#

Permet de nommer les cubes dans la collection

    bpy.context.object.name = nom
#

quadrants = plans de decoupe(x,y,z)avec des cubes

def quadrants(x, y, z):

    cube_b = cube(x + 1, y + 1, z + 3, "cube_b")
    liste2.append(cube_b)
#

Permet de joindre tout les cubes du quadrant et changer son origine pour les rotations

    Edit()

    cube_c = cube(x + 3, y + 1, z + 1, "cube_c")
    liste2.append(cube_c)

    cube_d = cube(x + 1, y + 3, z + 1, "cube_d")
    liste2.append(cube_d)

    cube_e = cube(x + 3, y + 3, z + 3, "quadrants")
    liste2.append(cube_e)

    Edit()
    bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS", center="MEDIAN")
#

Le cube principale qui va être en continuité

def cube_centre(x, y, z):

    cube_a = cube(x + 2, y + 2, z + 2, "cube_centre")
#

Création d’une liste avec les cubes centres

    liste1.append(cube_a)
#

Reprendre notre interprétation du divisibility1

def Divisibility1(x, y, z):

    quadrants(x, y, z)
    cube_centre(x, y, z)
    Rotation_aléatoire(cube_centre)
    Boolean("cube_centre", "quadrants")
    delete_quadrants("cube_b", "cube_c", "cube_d", "quadrants")
#

Appliquer une rotation des quadrants selon la rotation du cube_a precedent

def module2(x, y, z, r_prec, t_prec, n):
#

Création des quadrants

    quadrants(x, y, z)
#

La rotation du premier quadrant se fait aléatoirement

    if n <= 0:
        Rotation_aléatoire(quadrants)
    else:
#

Rotation des quadrants qui suivent se font par rapport à la rotation aléatoire du cube centre prècedent

        Rotation_centre(r_prec, t_prec, quadrants)

    cube_centre(x, y, z)
    r, t = Rotation_xy(cube_centre)

    Boolean("cube_centre", "quadrants")
    delete_quadrants("cube_b", "cube_c", "cube_d", "quadrants")

    return r, t
#

On utilise return pour reprende les données des rotations des cubes centraux pour les réutiliser sur les quadrants

#

Création du Divisibility2 avec continuité

def Divisibility2(x, y, z):
#

Premier Division sans les rotations des quadrants (On reprend DivisibilityI pour créer le Divisibility2)

    Divisibility1(-1, -1, -1)

    r_prec = 0
    t_prec = 0
#

Boucle avec continuité: les quadrants du deuxième cube reprend la rotation du premier cube centre. Cela permet de diviser le deuxieme cube par rapport au premier.

    for n in range(0, 2, 1):

        r_prec, t_prec = module2(x + n, y + n, z + n, r_prec, t_prec, n)
#

Début de Divisibility3 Le principe est de reprendre Divisibility2 pour créer le Divisibility3. Le Divisibility2 devient alors des arrêtes du cubes 10 x 10

def dessiner_arrete(num_arrete, x, y, z, r_prec, t_prec):
#

Chaques Divisibility2 créent une des arrêtes du cube 10 x 10 (12 arrêtes au total)

    if num_arrete == 0:
        for n in range(0, 4, 1):
#

V1 (nom de l’arrete = voir image)

            r_prec, t_prec = module2(x, y, z + 6 - 1.5 * n, r_prec, t_prec, n)
    elif num_arrete == 1:
        for n in range(0, 4, 1):
#

V2

            r_prec, t_prec = module2(x + 6, y, z + 6 - 1.5 * n, r_prec, t_prec, n)
    elif num_arrete == 2:
        for n in range(0, 4, 1):
#

V3

            r_prec, t_prec = module2(x + 6, y + 6, z + 1.5 * n, r_prec, t_prec, n)
    elif num_arrete == 3:
        for n in range(0, 4, 1):
#

V4

            r_prec, t_prec = module2(x, y + 6, z + 6 - 1.5 * n, r_prec, t_prec, n)
    elif num_arrete == 4:
        for n in range(0, 4, 1):
#

H1

            r_prec, t_prec = module2(x + 1.5 * n, y, z, r_prec, t_prec, n)
    elif num_arrete == 5:
        for n in range(0, 4, 1):
#

H2

            r_prec, t_prec = module2(x + 6, y + 1.5 * n, z, r_prec, t_prec, n)
    elif num_arrete == 6:
        for n in range(0, 4, 1):
#

H3

            r_prec, t_prec = module2(x + 1.5 * n, y + 6, z, r_prec, t_prec, n)
    elif num_arrete == 7:
        for n in range(0, 4, 1):
#

H4

            r_prec, t_prec = module2(x, y + 1.5 * n, z, r_prec, t_prec, n)
    elif num_arrete == 8:
        for n in range(0, 4, 1):
#

H5

            r_prec, t_prec = module2(x + 1.5 * n, y, z + 6, r_prec, t_prec, n)
    elif num_arrete == 9:
        for n in range(0, 4, 1):
#

H6

            r_prec, t_prec = module2(x + 6, y + 1.5 * n, z + 6, r_prec, t_prec, n)
    elif num_arrete == 10:
        for n in range(0, 4, 1):
#

H7

            r_prec, t_prec = module2(x + 6 - 1.5 * n, y + 6, z + 6, r_prec, t_prec, n)
    elif num_arrete == 11:
        for n in range(0, 4, 1):
#

H8

            r_prec, t_prec = module2(x, y + 1.5 * n, z + 6, r_prec, t_prec, n)
#

Lorsque l’une des arrêtes est génerer, on le prècise avec True dans la liste bool_dessine crée au début du code

    liste_bool_dessine[num_arrete] = True
#

Création de Divisibility 3

def Divisibility3(x, y, z):
#

On a déterminer tout les mouvemments possibles entre les arrêtes et en créer une liste Chaque arrête est en connection avec 4 autres arrêtes Cela nous permet de créer une continuité entre les arrétes générer.

    liste_mouv_possible_V1 = [4, 7, 8, 11]
    liste_mouv_possible_V2 = [4, 5, 8, 9]
    liste_mouv_possible_V3 = [5, 6, 9, 10]
    liste_mouv_possible_V4 = [6, 7, 10, 11]
    liste_mouv_possible_H1 = [0, 1, 5, 7]
    liste_mouv_possible_H2 = [1, 2, 4, 6]
    liste_mouv_possible_H3 = [2, 3, 5, 7]
    liste_mouv_possible_H4 = [0, 3, 4, 6]
    liste_mouv_possible_H5 = [0, 1, 9, 11]
    liste_mouv_possible_H6 = [1, 2, 8, 10]
    liste_mouv_possible_H7 = [2, 3, 9, 11]
    liste_mouv_possible_H8 = [0, 3, 8, 10]
#

Réunir tout les mouvements dans une liste

    listes_mouv_possibles = [
        liste_mouv_possible_V1,
        liste_mouv_possible_V2,
        liste_mouv_possible_V3,
        liste_mouv_possible_V4,
        liste_mouv_possible_H1,
        liste_mouv_possible_H2,
        liste_mouv_possible_H3,
        liste_mouv_possible_H4,
        liste_mouv_possible_H5,
        liste_mouv_possible_H6,
        liste_mouv_possible_H7,
        liste_mouv_possible_H8,
    ]

    r_prec = 0
    t_prec = 0
#

Boucle qui crée 6 arrêtes en connexion

    for etape in range(0, 6, 1):
#

Selection de la première arrëte aléatoirement

        if etape == 0:
            arrete_actuel = randint(0, 11)
#

Création des 5 arrëtes suivants en connexion

        else:
#

Création d’une liste qui stock tout les ‘False’, c4est a dire les arrêtes qui ne sont pas encore selectionné dans la boucle

            liste_disponibles = []
#

i = selectionne sur ’ possibilités les qrrêtes qui ne sont pas encore selectionnées

            for i in range(0, 3, 1):
#

Si dans la liste_bool_dessine(créer tout au début du code), les arrêtes ne sont pas encore génerées, on le stock dqns une nouvelle liste (liste_disponibles)

                if liste_bool_dessine[listes_mouv_possibles[arrete_actuel][i]] == False:
                    liste_disponibles.append(listes_mouv_possibles[arrete_actuel][i])
#

l’arrête_actuel générée va alors prendre un chemin aléatoire mais en connexion avec l’arrête prècédent De plus, il ne générera pas une arrête déjà créé dqns lq boucle.

            arrete_actuel = liste_disponibles[randint(0, len(liste_disponibles) - 1)]
#

Execution de la définition par rapport à l’arrête prècedent

        dessiner_arrete(arrete_actuel, x, y, z, r_prec, t_prec)
#

Execution du programme :

nettoyage()
#

Différentes étapes de l’oeuvre:

#

quadrants(0,0,0) cube_centre(0,0,0) Divisibility1(0,0,0) Divisibility2(0,0,0)

Divisibility3(0, 0, 0)
#

Imprimer les listes:

print(liste1)
print(liste2)
#

Choisir l’angle de la caméra:

#

axoCam (‘axonometrique’,’isometrie’)

axoCam("axonometrique", "trimetrie")